]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Add ISO week dates to the calendar
authorRaphael Bosshard <raphael.bosshard@gmail.com>
Thu, 27 May 2010 07:31:46 +0000 (09:31 +0200)
committerFlorian Müllner <fmuellner@src.gnome.org>
Thu, 27 May 2010 23:31:33 +0000 (01:31 +0200)
This patch adds ISO week dates to the calendar. Week dates are an
often used feature in business and government offices. Can be turned
on through gconf, off by default.

https://bugzilla.gnome.org/show_bug.cgi?id=603532

data/gnome-shell.schemas
data/theme/gnome-shell.css
js/ui/calendar.js
js/ui/panel.js

index 8e5c91f7f484e83021fd7c25160ba6a8a1966e30..434986fa57ad06f16488774558e3cba18ae0dfe6 100644 (file)
         </locale>
       </schema>
 
+      <!-- Calendar -->
+      <schema>
+        <key>/schemas/desktop/gnome/shell/calendar/show_weekdate</key>
+          <applyto>/desktop/gnome/shell/calendar/show_weekdate</applyto>
+          <owner>gnome-shell</owner>
+          <type>bool</type>
+          <default>false</default>
+          <locale name="C">
+            <short>Show the week date in the calendar</short>
+            <long>
+              If true, display the ISO week date in the calendar.
+            </long>
+          </locale>
+      </schema>
   </schemalist>
 
 </gconfschemafile>
index bee6c9feedebeb248081d7cbb017c0729c1602dc..c34ae630d0adca09b08a32f183cb2018f48e10c4 100644 (file)
@@ -899,6 +899,10 @@ StTooltip {
     padding: 0px 4px 2px 0px;
 }
 
+.calendar-calendarweek {
+    color: #666666;
+}
+
 /* App Switcher */
 #altTabPopup {
     padding: 8px;
index 8122e506f750edd06ca381989dce411295a605fc..080ab1dedb0e932c99ae010046de9d5ebdb61a99 100644 (file)
@@ -3,10 +3,14 @@
 const Clutter = imports.gi.Clutter;
 const Lang = imports.lang;
 const St = imports.gi.St;
-
+const Pango = imports.gi.Pango;
+const Shell = imports.gi.Shell;
 const Gettext_gtk20 = imports.gettext.domain('gtk20');
 
 const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
+const MSECS_IN_WEEK = MSECS_IN_DAY * 7;
+const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
+const SHOW_WEEKDATE_KEY = 'calendar/show_weekdate';
 
 function _sameDay(dateA, dateB) {
     return (dateA.getDate() == dateB.getDate() &&
@@ -14,6 +18,24 @@ function _sameDay(dateA, dateB) {
             dateA.getYear() == dateB.getYear());
 }
 
+function _getCalendarWeekForDate(date) {
+    let startOfYear = new Date(date.getFullYear(), 0, 1);
+    let sday = startOfYear.getDay();
+    let offset = 4 + (7 * Math.floor(sday * (1/5))) - sday;
+    let firstThursday = new Date(date.getFullYear(), 0, 1 + offset);
+    let weekOfYear = Math.ceil((date.getTime() - firstThursday.getTime()) / MSECS_IN_WEEK);
+    return weekOfYear;
+}
+
+function _getDigitWidth(actor){
+    let context = actor.get_pango_context();
+    let themeNode = actor.get_theme_node();
+    let font = themeNode.get_font();
+    let metrics = context.get_metrics(font, context.get_language());
+    let width = metrics.get_approximate_digit_width();
+    return width;
+}
+
 function Calendar() {
     this._init();
 }
@@ -24,6 +46,13 @@ Calendar.prototype = {
         // GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
         // should add a C function so we can do the full handling.
         this._weekStart = NaN;
+        this._weekdate = NaN;
+        this._digitWidth = NaN;
+        this._gconf = Shell.GConf.get_default();
+
+        this._gconf.connect('changed', Lang.bind(this, this._onSettingsChange));
+        this._useWeekdate = this._gconf.get_boolean(SHOW_WEEKDATE_KEY);
+
         let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0');
         if (weekStartString.indexOf('calendar:week_start:') == 0) {
             this._weekStart = parseInt(weekStartString.substring(20));
@@ -58,11 +87,28 @@ Calendar.prototype = {
         this.actor.connect('scroll-event',
                            Lang.bind(this, this._onScroll));
 
+        this._buildHeader ();
+        this._update();
+    },
+
+    // Sets the calendar to show a specific date
+    setDate: function(date) {
+        if (!_sameDay(date, this.date)) {
+            this.date = date;
+            this._update();
+        }
+    },
+
+    _buildHeader: function() {
+        let offsetCols = this._useWeekdate ? 1 : 0;
+        this.actor.destroy_children();
+
         // Top line of the calendar '<| September 2009 |>'
         this._topBox = new St.BoxLayout();
         this.actor.add(this._topBox,
-                       { row: 0, col: 0, col_span: 7 });
+                       { row: 0, col: 0, col_span: offsetCols + 7 });
 
+        this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
         let [backlabel, forwardlabel] = ['&lt;', '&gt;'];
         if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
             [backlabel, forwardlabel] = [forwardlabel, backlabel];
@@ -85,25 +131,39 @@ Calendar.prototype = {
         let iter = new Date(this.date);
         iter.setSeconds(0); // Leap second protection. Hah!
         iter.setHours(12);
+
+        if (this._useWeekdate) {
+            this._weekdateHeader = new St.Label();
+            this.actor.add(this._weekdateHeader,
+                              { row: 1,
+                                col: 0,
+                                x_fill: false, x_align: St.Align.MIDDLE });
+            this._setWeekdateHeaderWidth();
+        } else {
+            this._weekdateHeader = null;
+        }
+
         for (let i = 0; i < 7; i++) {
             this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
                            { row: 1,
-                             col: (7 + iter.getDay() - this._weekStart) % 7,
+                             col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
                              x_fill: false, x_align: St.Align.END });
             iter.setTime(iter.getTime() + MSECS_IN_DAY);
         }
 
         // All the children after this are days, and get removed when we update the calendar
         this._firstDayIndex = this.actor.get_children().length;
+    },
 
-        this._update();
+    _onStyleChange: function(actor, event) {
+        // width of a digit in pango units
+        this._digitWidth = _getDigitWidth(this.actor) / Pango.SCALE;
+        this._setWeekdateHeaderWidth();
     },
 
-    // Sets the calendar to show a specific date
-    setDate: function(date) {
-        if (!_sameDay(date, this.date)) {
-            this.date = date;
-            this._update();
+    _setWeekdateHeaderWidth: function() {
+        if (this.digitWidth != NaN && this._useWeekdate && this._weekdateHeader) {
+            this._weekdateHeader.set_width (this._digitWidth * WEEKDATE_HEADER_WIDTH_DIGITS);
         }
     },
 
@@ -140,6 +200,12 @@ Calendar.prototype = {
         this._update();
     },
 
+    _onSettingsChange: function() {
+        this._useWeekdate = this._gconf.get_boolean(SHOW_WEEKDATE_KEY);
+        this._buildHeader();
+        this._update();
+    },
+
     _update: function() {
         this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
 
@@ -166,10 +232,20 @@ Calendar.prototype = {
                 label.style_class = 'calendar-day calendar-other-month-day';
             else
                 label.style_class = 'calendar-day';
+
+            let offsetCols = this._useWeekdate ? 1 : 0;
             this.actor.add(label,
-                           { row: row, col: (7 + iter.getDay() - this._weekStart) % 7,
+                           { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
                              x_fill: false, x_align: St.Align.END });
 
+            if (this._useWeekdate && iter.getDay() == 4) {
+                let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
+                                           style_class: 'calendar-day calendar-calendarweek'});
+                this.actor.add(label,
+                              { row: row, col: 0,
+                                       x_fill: false, x_align: St.Align.MIDDLE });
+            }
+
             iter.setTime(iter.getTime() + MSECS_IN_DAY);
             if (iter.getDay() == this._weekStart) {
                 // We stop on the first "first day of the week" after the month we are displaying
index 58e1d5f3ce85dbd7d0eb018f7d6fdd6673125dd8..0a6a484fe47ec01d86112f8503838cf0722d012d 100644 (file)
@@ -1268,6 +1268,7 @@ CalendarPopup.prototype = {
         Main.chrome.addActor(this.actor, { visibleInOverview: true,
                                            affectsStruts: false });
         this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
+        this.calendar.actor.connect('notify::width', Lang.bind(this, this._centerPopup));
     },
 
     show: function() {
@@ -1276,7 +1277,7 @@ CalendarPopup.prototype = {
         // Reset the calendar to today's date
         this.calendar.setDate(new Date());
 
-        this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
+        this._centerPopup();
         this.actor.lower(panelActor);
         this.actor.show();
         Tweener.addTween(this.actor,
@@ -1296,5 +1297,10 @@ CalendarPopup.prototype = {
                            onComplete: function() { this.actor.hide(); },
                            onCompleteScope: this
                          });
+    },
+
+    _centerPopup: function() {
+        let panelActor = Main.panel.actor;
+        this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
     }
 };